package cn.wanda.bi.sunshine.platform.server.service.authorize;

import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.apache.commons.collections.CollectionUtils;
import org.apache.shiro.codec.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import cn.wanda.bi.sunshine.platform.server.SunshineCode;
import cn.wanda.bi.sunshine.platform.server.bean.KeyCache;
import cn.wanda.bi.sunshine.platform.server.bean.mapper.AdminMapper;
import cn.wanda.bi.sunshine.platform.server.bean.mapper.AdminThirdMapper;
import cn.wanda.bi.sunshine.platform.server.bean.mapper.MemberThirdMapper;
import cn.wanda.bi.sunshine.platform.server.bean.model.Admin;
import cn.wanda.bi.sunshine.platform.server.bean.model.AdminExample;
import cn.wanda.bi.sunshine.platform.server.bean.model.AdminThird;
import cn.wanda.bi.sunshine.platform.server.bean.model.AdminThirdExample;
import cn.wanda.bi.sunshine.platform.server.bean.model.MemberThird;
import cn.wanda.bi.sunshine.platform.server.bean.model.MemberThirdExample;
import cn.wanda.bi.sunshine.platform.server.client.wrapper.AuthClientWrapper;
import cn.wanda.bi.sunshine.platform.server.client.wrapper.LoginWrapper;
import cn.wanda.bi.sunshine.platform.server.controller.response.AdminLoginResponse;
import cn.wanda.bi.sunshine.platform.server.controller.response.MemberLoginResponse;
import cn.wanda.bi.sunshine.platform.server.controller.response.WechatAuthResponse;
import cn.wanda.bi.sunshine.platform.server.controller.response.common.SimpleResponse;
import cn.wanda.bi.sunshine.platform.server.utils.JsonUtil;
import cn.wanda.bi.sunshine.platform.server.utils.exception.ClientException;
import cn.wanda.bi.sunshine.platform.server.utils.exception.SunshineException;

/**
 * Created by wangfupeng1
 */
@Service
public class WechatAuthService {

	public static final Logger logger = LoggerFactory.getLogger(WechatAuthService.class);

	@Autowired
	private AuthClientWrapper authClientWrapper;
	@Autowired
	private LoginWrapper loginWrapper;
	@Autowired
	private MemberThirdMapper memberThirdMapper;
	@Autowired
	private AdminThirdMapper adminThirdMapper;
	@Autowired
	private AdminMapper adminMapper;

	@Cacheable(value = "cache:wechat", key = "'cache:wechat:appid:'+#appid+':url:'+#url+':type:'+#type")
	public SimpleResponse memberSignature(String appid, String url, String type) {
		if (type.equals("WECHAT")) {
			String accessToken = authClientWrapper.getAccessToken(appid);
			String jsapi_ticket = authClientWrapper.getJsApiTicket(accessToken);
			String timestamp = Long.toString(System.currentTimeMillis() / 1000);
			String nonceStr = UUID.randomUUID().toString().replaceAll("-", "");
			String signature = authClientWrapper.getSignature(jsapi_ticket, nonceStr, timestamp, url);
			WechatAuthResponse wechatAuthResponse = new WechatAuthResponse();
			wechatAuthResponse.setUrl(url);
			wechatAuthResponse.setJsapi_ticket(jsapi_ticket);
			wechatAuthResponse.setNonceStr(nonceStr);
			wechatAuthResponse.setTimestamp(timestamp);
			wechatAuthResponse.setSignature(signature);
			wechatAuthResponse.setAppid(appid);
			return SimpleResponse.success(wechatAuthResponse);
		}
		return SimpleResponse.success();
	}

	@Cacheable(value = "cache:wechat", key = "'cache:wechat:memberlogin:appid:'+#appid+':code:'+#code+':type:'+#type")
	public SimpleResponse memberLogin(String appid, String code, String type) {
		if (type.equals("WECHAT")) {
			Map<String, String> map = authClientWrapper.getOpenId(appid, code);
			String openId = map.get("openid");
			MemberThirdExample memberThirdExample = new MemberThirdExample();
			memberThirdExample.createCriteria().andThirdAppIdEqualTo(appid).andThirdOpenIdEqualTo(openId);
			List<MemberThird> memberThirds = memberThirdMapper.selectByExample(memberThirdExample);
			if (CollectionUtils.isEmpty(memberThirds))
				throw new SunshineException(SunshineCode.WECHAT_ERROR_NOT_FOUND_BIND_MEMBER);
			MemberThird memberThird = memberThirds.get(0);
			return wechatMemberResponse(memberThird, openId, appid);
		}
		return SimpleResponse.success();
	}

	public SimpleResponse<MemberLoginResponse> memberBind(String appid, String code, String mobile,
			String verifyCode, String type) {
		if (type.equals("WECHAT")) {
			SimpleResponse response = loginWrapper.checkVerifyCode(mobile, verifyCode, 2);
			if (response.getStatus() != 200)
				throw new ClientException(response.getStatus(), response.getMessage());
			Map<String, String> map = authClientWrapper.getOpenId(appid, code);
			String openId = map.get("openid");
			MemberThirdExample memberThirdExample = new MemberThirdExample();
			memberThirdExample.createCriteria().andUserMobileEqualTo(mobile).andTypeEqualTo("WECHAT")
					.andThirdAppIdEqualTo(appid);
			List<MemberThird> memberThirds = memberThirdMapper.selectByExample(memberThirdExample);
			MemberThird memberThird = new MemberThird();
			if (CollectionUtils.isEmpty(memberThirds)) {
				memberThird.setType("WECHAT");
				memberThird.setUserMobile(mobile);
				memberThird.setThirdAppId(appid);
				memberThird.setThirdOpenId(openId);
				memberThirdMapper.insertSelective(memberThird);
			} else {
				memberThird = memberThirds.get(0);
				memberThird.setThirdOpenId(openId);
				memberThirdMapper.updateByPrimaryKeySelective(memberThird);
			}
			return wechatMemberResponse(memberThird, openId, appid);
		}
		return SimpleResponse.success();
	}

	public SimpleResponse wechatMemberResponse(MemberThird memberThird, String openId, String appid) {
		Map<String, String> mapToken = new HashMap<String, String>();
		mapToken.put("mobile", memberThird.getUserMobile());
		mapToken.put("loginTime", Calendar.getInstance().getTime().getTime() + "");
		mapToken.put("openId", openId);
		mapToken.put("appId", appid);
		MemberLoginResponse memberLoginResponse = new MemberLoginResponse();
		String token = Base64.encodeToString(JsonUtil.toJson(mapToken).getBytes());
		memberLoginResponse.setMemberToken(token);
		memberLoginResponse.setOpenId(openId);
		return SimpleResponse.success(memberLoginResponse);
	}

	@Cacheable(value = "cache:wechat", key = "'cache:wechat:userinfo:appid:'+#appid+':code:'+#code+':type:'+#type")
	public SimpleResponse memberUserInfo(String appid, String code, String type) {
		if(type.equals("WECHAT")){
			Map<String, String> map = authClientWrapper.getOpenId(appid, code);
			String openId = map.get("openid");
			Map<String, String> mapUnion = authClientWrapper.getUserInfo(openId, authClientWrapper.getAccessToken(appid));
			return SimpleResponse.success(mapUnion);
		}
		return SimpleResponse.success();
	}

	@Cacheable(value = "cache:wechat", key = "'cache:wechat:adminlogin:appid:'+#appid+':code:'+#code+':type:'+#type")
	public SimpleResponse<AdminLoginResponse> adminLogin(String appid, String code, String type) {
		if (type.equals("WECHAT")) {
			Map<String, String> map = authClientWrapper.getOpenId(appid, code);
			String openId = map.get("openid");
			AdminThirdExample adminThirdExample = new AdminThirdExample();
			adminThirdExample.createCriteria().andThirdAppIdEqualTo(appid).andThirdOpenIdEqualTo(openId);
			List<AdminThird> adminThirds = adminThirdMapper.selectByExample(adminThirdExample);
			if (CollectionUtils.isEmpty(adminThirds))
				throw new SunshineException(SunshineCode.WECHAT_ERROR_NOT_FOUND_BIND_ADMIN);
			AdminThird adminThird = adminThirds.get(0);
			return adminResponse(adminThird, openId, appid);
		}
		return SimpleResponse.success();
	}

	public SimpleResponse adminBind(String appid, String code, String userName, String password, String type) {
		if (type.equals("WECHAT")) {
			AdminExample adminExample = new AdminExample();
			adminExample.createCriteria().andAdminNameEqualTo(userName).andAdminPasswordEqualTo(password);
			List<Admin> admins = adminMapper.selectByExample(adminExample);
			if (CollectionUtils.isEmpty(admins))
				throw new SunshineException(SunshineCode.LOCAL_AUTH_ERROR_MEMBER_NAME_OR_PASSWORD_INCORRECT);
			Admin admin = admins.get(0);
			return adminBind(appid, code, admin, userName, password);
		}
		return SimpleResponse.success();
	}

	public SimpleResponse adminBind(String appid, String code, Admin admin, String userName, String password) {
		Map<String, String> map = authClientWrapper.getOpenId(appid, code);
		String openId = map.get("openid");
		AdminThirdExample adminThirdExample = new AdminThirdExample();
		adminThirdExample.createCriteria().andAdminNameEqualTo(userName).andTypeEqualTo("WECHAT")
				.andThirdAppIdEqualTo(appid);
		List<AdminThird> adminThirds = adminThirdMapper.selectByExample(adminThirdExample);
		AdminThird adminThird = new AdminThird();
		if (CollectionUtils.isEmpty(adminThirds)) {
			adminThird.setType("WECHAT");
			adminThird.setAdminName(userName);
			adminThird.setThirdAppId(appid);
			adminThird.setThirdOpenId(openId);
			adminThirdMapper.insertSelective(adminThird);
		} else {
			adminThird = adminThirds.get(0);
			adminThird.setThirdOpenId(openId);
			adminThirdMapper.updateByPrimaryKeySelective(adminThird);
		}
		return adminResponse(adminThird, openId, appid);
	}

	public SimpleResponse adminResponse(AdminThird adminThird, String openId, String appid) {
		Map<String, String> mapToken = new HashMap<String, String>();
		mapToken.put("adminName", adminThird.getAdminName());
		mapToken.put("loginTime", Calendar.getInstance().getTime().getTime() + "");
		mapToken.put("openId", openId);
		mapToken.put("appId", appid);
		AdminLoginResponse adminLoginResponse = new AdminLoginResponse();
		String token = Base64.encodeToString(JsonUtil.toJson(mapToken).getBytes());
		adminLoginResponse.setAdminToken(token);
		adminLoginResponse.setOpenId(openId);
		return SimpleResponse.success(adminLoginResponse);
	}

}
